home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Camelot
/
Camelot 084 (1990-10)(Swedish User Group of Amiga)(SE)(PD)[WB].zip
/
Camelot 084 (1990-10)(Swedish User Group of Amiga)(SE)(PD)[WB].adf
/
MakeC
/
iff_stuff.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-09-20
|
9KB
|
265 lines
/*
These are some IFF file handler routines...
*/
#ifndef IFF_H
#include "iff.h"
#endif
UBYTE iff_disk_buffer[4096]; /* a 4K disk buffer to speed I/O to file */
SHORT iff_buffer_size; /* these are not used at the moment */
SHORT iff_buffer_position; /* but I figure they may come in handy */
ULONG iff_file_position; /* sometime. Only 6 bytes, no biggie */
/*
PullID() is done here as an actual subroutine, although it could just
as easily be set up as a macro with a #define. All it does is takes
a pointer to a text buffer and yanks out the first four bytes and
shifts them into a ULONG, then returns it.
*/
ULONG PullID(what)
UBYTE *what;
{
return (ULONG)((ULONG)what[0]<<24 | (ULONG)what[1]<<16 | (ULONG)what[2]<<8 | (ULONG)what[3]);
}
/*
GetBMHD() takes a FILE pointer to an IFF file, and a pointer to a
BitMapHeader. It then searches the IFF file for the header and reads
the information into the BitMapHeader, one field at a time. This
coud be made considerably faster and simpler by doing a memcpy() from
the disk buffer instead, but this way makes it more clear what is in
the BitMapHeader and the relative positions within the file, so I'll
leave it like it is.
*/
BOOL GetBMHD(ifffile,header)
FILE *ifffile;
BitMapHeader *header;
{
Chunk bmhdchunk;
BOOL error;
/* first find the chunk */
error=FindChunk(ifffile,MakeID('B','M','H','D'),&bmhdchunk);
if(error)
return TRUE; /* read the data into header */
header->w = ((UWORD)(bmhdchunk.ckdata[0]) << 8) | (bmhdchunk.ckdata[1]);
header->h = ((UWORD)(bmhdchunk.ckdata[2]) << 8) | (bmhdchunk.ckdata[3]);
header->x = ((WORD)(bmhdchunk.ckdata[4]) << 8) | (bmhdchunk.ckdata[5]);
header->y = ((WORD)(bmhdchunk.ckdata[6]) << 8) | (bmhdchunk.ckdata[7]);
header->nplanes = bmhdchunk.ckdata[8];
header->masking = bmhdchunk.ckdata[9];
header->compression = bmhdchunk.ckdata[10];
header->pad1 = 0; /* set to 0 and skip over a byte */
header->TransparentColor = (UWORD)(bmhdchunk.ckdata[12] << 8) | (bmhdchunk.ckdata[13]);
header->xAspect = bmhdchunk.ckdata[14];
header->yAspect = bmhdchunk.ckdata[15];
header->pageWidth = ((WORD)(bmhdchunk.ckdata[16]) << 8) | (bmhdchunk.ckdata[17]);
header->pageHeight = ((WORD)(bmhdchunk.ckdata[18]) << 8) | (bmhdchunk.ckdata[19]);
FreeMem(bmhdchunk.ckdata,bmhdchunk.cksize); /* free memory */
return FALSE;
}
/*
GetViewModes() looks for a CAMG chunk in the IFF file. If it finds
one, it stores the ViewModes word into the NewScreen structure. If
there isn't, it sets up the minimal assumptions necessary to open the
screen properly (i.e. lace or not and hires or not).
*/
BOOL GetViewModes(newscreen,ifffile)
struct NewScreen *newscreen;
FILE *ifffile;
{
BOOL error = FALSE;
Chunk camgchunk;
error = FindChunk(ifffile,MakeID('C','A','M','G'),&camgchunk);
if(!error)
{
newscreen->ViewModes = PullID(camgchunk.ckdata) & CAMGMASK;
FreeMem(camgchunk.ckdata,camgchunk.cksize);
}
if(newscreen->Width > 384) /* if no CAMG chunk, make it up */
newscreen->ViewModes |= HIRES; /* if there was one, this won't */
if(newscreen->Height > 200) /* hurt anything to double-check */
newscreen->ViewModes |= LACE;
return FALSE;
}
/*
FindChunk searches an IFF file for a chunk of type chunktype. It
makes use of the iff_disk_buffer for speedier I/O. The buffer
could be diddled with a little to improve speed, but you might wind
up with overkill on the reads (probably already a lot of that at 4K).
If it finds the chunk, it allocates memory for the chunk body
UNLESS it is a BODY type chunk. It then reads the data into the
chunkdata section and returns. It is up to the caller to free the
allocated memory. If it is looking for a BODY type chunk, rather than
allocate memory for the body, it leaves this part up to the caller
(useful for on-the-fly decompression), and instead positions the
IFF file pointer so that it points to the start of the BODY chunk data.
*/
BOOL FindChunk(ifffile,chunktype,chunk)
FILE *ifffile;
ULONG chunktype;
Chunk *chunk;
{
SHORT temppos;
BOOL foundchunk= FALSE;
ULONG bytes_read=0,seek_spot=0;
SHORT buffer_size=0;
rewind(ifffile); /* start at top of file */
buffer_size = fread(iff_disk_buffer,1,4096,ifffile); /* fill buffer */
while(TRUE) /* search whole file for chunk */
{
for(temppos=0;temppos<buffer_size;temppos++) /* scan buffer */
if(PullID(&iff_disk_buffer[temppos]) == chunktype)
{
foundchunk = TRUE; /* found chunk type ? */
break;
}
if((foundchunk) || feof(ifffile)) /* done ? */
break;
buffer_size = fread(iff_disk_buffer,1,4096,ifffile);
bytes_read += buffer_size; /* how far are we into file? */
};
seek_spot = bytes_read + temppos + 8; /* for a BODY chunk */
if(foundchunk)
{
chunk->ckID = PullID(&iff_disk_buffer[temppos]);
chunk->cksize = PullID(&iff_disk_buffer[temppos+4]);
if(chunk->ckID == MakeID('B','O','D','Y'))
{
chunk->ckdata = NULL; /* fix file pointer */
fseek(ifffile,seek_spot,SEEK_SET);
return FALSE; /* I'm outta here... */
}
chunk->ckdata = (UBYTE *)AllocMem(chunk->cksize,MEMF_CLEAR);
if(chunk->ckdata == NULL) /* not a BODY chunk at this point */
{
printf("\nNo memory for chunk!!\n");
return TRUE;
}
temppos += 8; /* read the data into the chunkdata section */
for(bytes_read=0;bytes_read<chunk->cksize;bytes_read++)
chunk->ckdata[bytes_read] = iff_disk_buffer[temppos++];
}
else
return TRUE; /* hey, somethin' ain't right */
return FALSE; /* everything's fine */
}
/*
GetColorMap scans an IFF file for a colormap, loading it into the
colortable given. It returns the number of colors in the table.
*/
SHORT GetColorMap(ifffile,colortable)
FILE *ifffile;
UWORD *colortable;
{
Chunk cmapchunk;
SHORT count=0;
BOOL error = FALSE;
UWORD red,green,blue;
error = FindChunk(ifffile,MakeID('C','M','A','P'),&cmapchunk);
if(!error) /* found colormap? */
{ /* make RGB4's out of it */
for(;count<cmapchunk.cksize/3;count++)
{
red = cmapchunk.ckdata[(count*3)] >> 4; /* use high order 4 bits */
green = cmapchunk.ckdata[(count*3)+1] >> 4;
blue = cmapchunk.ckdata[(count*3)+2] >> 4;
colortable[count] = blue;
colortable[count] |= green << 4;
colortable[count] |= red << 8;
}
FreeMem(cmapchunk.ckdata,cmapchunk.cksize);
}
return (count);
}
/*
ReadPic() is the picture reader. It takes a pointer to a bitmap, a
pointer to a file which need not be at any particular position, (it
will find the data with FindChunk()), and a pointer to a BitMapHeader
describing the picture being read.
It doesn't matter whether the picture is on or off screen or whether
it is not the same size as the bitmap. If it is too small, it is read
anyway. If it is too large, it is clipped at the BitMap boundaries.
Compressed and masked images are handled correctly.
*/
BOOL ReadPic(bitmap,ifffile,header)
struct BitMap *bitmap;
FILE *ifffile;
BitMapHeader *header;
{
BOOL error = FALSE;
BOOL mask = FALSE;
BOOL compress = FALSE;
Chunk bodychunk;
SHORT scanline,plane,count,needed,read;
BYTE data,run;
UBYTE bit_bucket[255];
UBYTE *dest;
if(header->masking == mskHasMask)
mask = TRUE; /* got a mask on it ?*/
if(header->compression == cmpByteRun1)
compress = TRUE; /* compressed via ByteRun1? */
needed = header->w/8; /* how many BYTES do we need? */
if(header->w%8) /* if odd number of pixels, */
needed++; /* adjust that number */
error = FindChunk(ifffile,MakeID('B','O','D','Y'),&bodychunk);
if(error)
return TRUE; /* YIKES! No Body! */
for(scanline=0;scanline<header->h;scanline++) /* lines first */
for(plane=0;plane<header->nplanes;plane++) /* then planes */
{
if(mask & scanline%2) /* ignore mask */
dest = bit_bucket; /* toss mask planes */
else /* figure scanline in bitmap */
dest = bitmap->Planes[plane]+(scanline*bitmap->BytesPerRow);
if(!compress) /* not too likely, but easy */
for(count=0;count<needed;count++)
*dest++ = fgetc(ifffile);
else /* image is compressed */
{
count=0; /* count is bytes decompressed */
while(count<needed)
{
run = fgetc(ifffile); /* size of run */
if(run>=0) /* literal run */
{
count += run+1;
for(read=0;read<=run;read++)
*dest++ = fgetc(ifffile);
}
else if (run != 128) /* repeat run */
{
run = run*(-1);
count += run+1;
data = fgetc(ifffile);
for(read=0;read<=run;read++)
*dest++ = data;
}
}
}
}
return FALSE;
}